package com.joey.cloud.flowable.controller;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.joey.cloud.communal.utils.JoeDevUtils;
import com.joey.cloud.communal.utils.ResponseUtil;
import com.joey.cloud.communal.vo.PageIntVo;
import com.joey.cloud.communal.vo.PageLongVo;
import com.joey.cloud.flowable.acthi.entity.ActHiComment;
import com.joey.cloud.flowable.acthi.mapper.ActHiCommentMapper;
import com.joey.cloud.flowable.service.FlowProcessService;
import com.joey.cloud.flowable.service.FlowTaskService;
import com.joey.cloud.flowable.service.FlowUserService;
import com.joey.cloud.flowable.utils.FlowableUtils;
import com.joey.cloud.flowable.vo.FlowElementVo;
import com.joey.cloud.flowable.vo.TaskCommentVo;
import com.joey.cloud.flowable.vo.TaskVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Api(tags = "flow任务管理")
@Controller
@RequestMapping(value = "flowable/task")
@Slf4j
public class FlowableTaskController {
    @Resource
    RepositoryService repositoryService;
    @Resource
    RuntimeService runtimeService;
    @Resource
    TaskService taskService;
    @Resource
    HistoryService historyService;
    @Resource
    FlowUserService flowUserService;
    @Resource
    FlowProcessService flowProcessService;
    @Resource
    FlowTaskService flowTaskService;
    @Resource
    ActHiCommentMapper actHiCommentMapper;

    @ApiOperation(value = "批准任务流程")
    @ApiImplicitParams({
            @ApiImplicitParam(name="taskId",value="代办id",required=true,paramType="form"),
            @ApiImplicitParam(name="comment",value="审核意见",required=true,paramType="form"),
            @ApiImplicitParam(name="paramJson",value="流程变量参数序列化字符串",paramType="form")
    })
    @PostMapping(value = "applyTask")
    @ResponseBody
    public ResponseUtil applyTask(String taskId,String comment, String paramJson) {
        try {
            Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
            if (task == null) {
                return ResponseUtil.error("流程不存在");
            }
            HashMap<String, Object> param = null;
            if(StrUtil.isNotEmpty(paramJson)){
                param = JSONObject.parseObject(paramJson, HashMap.class);
            }else {
                param = new HashMap<>();
            }
            //通过审核
            flowTaskService.applyTask(task,comment,param);
            return ResponseUtil.success();
        }catch (Exception e){
            log.error("批准流程出错",e);
            return ResponseUtil.error();
        }
    }

    @ApiOperation(value = "跳转任务流程")
    @ApiImplicitParams({
            @ApiImplicitParam(name="processInstanceId",value="流程实例id",required=true,paramType="form"),
            @ApiImplicitParam(name="targetExecutionId",value="跳转流程节点id",required=true,paramType="form"),
            @ApiImplicitParam(name="comment",value="审核意见",required=true,paramType="form"),
            @ApiImplicitParam(name="taskStatus",value="meddle=干预reject=驳回return=退回",required=true,paramType="form")
    })
    @PostMapping(value = "jumpTask")
    @ResponseBody
    public ResponseUtil jumpTask(String processInstanceId,String targetExecutionId,String comment,String taskStatus) {
        try {
            flowTaskService.jumpTask(processInstanceId,targetExecutionId,taskStatus,comment);
            return ResponseUtil.success();
        }catch (Exception e){
            log.error("跳转流程出错",e);
            return ResponseUtil.error();
        }
    }

    @ApiOperation(value = "获取任务当前节点")
    @ApiImplicitParams({
            @ApiImplicitParam(name="processInstanceId",value="流程实例id",required=true,paramType="query")
    })
    @GetMapping(value = "queryCurrentFlowElement")
    @ResponseBody
    public ResponseUtil<FlowElementVo> queryCurrentFlowElement(String processInstanceId){
        try {
            if(StrUtil.isEmpty(processInstanceId)){
                return ResponseUtil.error("流程processInstanceId不能为空");
            }
            FlowElementVo vo = new FlowElementVo();
            ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
            if(pi!=null){
                Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
                if(task!=null){
                    vo.setTaskKey(task.getTaskDefinitionKey());
                    vo.setTaskName(task.getName());
                    vo.setAssignee(task.getAssignee());
                    vo.setAssigneeName(flowUserService.queryNameByUserIds(vo.getAssignee()));
                }
            }
            return ResponseUtil.success(vo);
        }catch (Exception e){
            log.error("获取当前节点出错，流程processInstanceId="+processInstanceId,e);
            return ResponseUtil.error();
        }
    }
    @ApiOperation(value = "获取任务上一个节点")
    @ApiImplicitParams({
            @ApiImplicitParam(name="processInstanceId",value="流程实例id",required=true,paramType="query")
    })
    @GetMapping(value = "queryLastFlowElement")
    @ResponseBody
    public ResponseUtil<TaskCommentVo> queryLastFlowElement(String processInstanceId){
        try {
            TaskCommentVo task = null;
            if(StrUtil.isEmpty(processInstanceId)){
                return ResponseUtil.error("流程processInstanceId不能为空");
            }
            QueryWrapper qw = new QueryWrapper();
            qw.eq("PROC_INST_ID_",processInstanceId);
            qw.isNotNull("TASK_ID_");
            qw.orderByDesc("TIME_");
            qw.last(" limit 3");
            List<ActHiComment> list = actHiCommentMapper.selectList(qw);
            if(list!=null&&list.size()>0){
                String taskId = list.get(0).getTaskId();
                task = getTaskCommentVo(taskId, list);
            }
            return ResponseUtil.success(task);
        }catch (Exception e){
            log.error("获取上一个节点出错，流程processInstanceId="+processInstanceId,e);
            return ResponseUtil.error();
        }
    }
    @ApiOperation(value = "获取任务下一个节点")
    @ApiImplicitParams({
            @ApiImplicitParam(name="processInstanceId",value="流程实例id",required=true,paramType="query")
    })
    @GetMapping(value = "queryNextFlowElement")
    @ResponseBody
    public ResponseUtil<List<FlowElementVo>> queryNextFlowElement(String processInstanceId){
        try {
            List<FlowElementVo> list = new ArrayList<>();
            if(StrUtil.isEmpty(processInstanceId)){
                return ResponseUtil.error("流程processInstanceId不能为空");
            }
            ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
            if(pi!=null){
                Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
                Map<String, Object> variables = runtimeService.getVariables(processInstanceId);
                List<UserTask> userTaskList = FlowableUtils.getNextUserTasks(repositoryService, task, variables);
                for(UserTask item:userTaskList){
                    FlowElementVo vo = new FlowElementVo();
                    vo.setTaskKey(item.getId());
                    vo.setTaskName(item.getName());
                    String expression = item.getAssignee();
                    if(StrUtil.isNotEmpty(expression)&&expression.trim().startsWith("${")){
                        Object str = variables.get(expression.substring(expression.lastIndexOf("{") + 1, expression.lastIndexOf("}")));
                        vo.setAssignee(JoeDevUtils.obj2Str(str));
                        vo.setAssigneeName(flowUserService.queryNameByUserIds(vo.getAssignee()));
                    }
                    list.add(vo);
                }
            }
            return ResponseUtil.success(list);
        }catch (Exception e){
            log.error("获取下一个节点出错，流程processInstanceId="+processInstanceId,e);
            return ResponseUtil.error();
        }
    }

    @ApiOperation(value = "获取流程定义的全部任务节点")
    @ApiImplicitParams({
            @ApiImplicitParam(name="processInstanceId",value="流程实例id",required=true,paramType="query")
    })
    @GetMapping(value = "queryFlowElementList")
    @ResponseBody
    public ResponseUtil<PageIntVo<FlowElementVo>> queryFlowElementList(String processInstanceId){
        try {
            if(StrUtil.isEmpty(processInstanceId)){
                return ResponseUtil.error("流程processInstanceId不能为空");
            }
            List<FlowElementVo> list = new ArrayList<>();
            ProcessInstance process = flowProcessService.getProcessInstanceById(processInstanceId);
            if(process!=null){
                ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(process.getProcessDefinitionId()).singleResult();
                BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
                Process mainProcess = bpmnModel.getMainProcess();
                Collection<FlowElement> flowElements = mainProcess.getFlowElements();
                if (CollectionUtils.isNotEmpty(flowElements)) {
                    Map<String, Object> variables = runtimeService.getVariables(processInstanceId);
                    for (FlowElement flowElement : flowElements) {
                        if (flowElement instanceof UserTask) {
                            FlowElementVo vo = new FlowElementVo(flowElement);
                            String expression = ((UserTask) flowElement).getAssignee();
                            if(StrUtil.isNotEmpty(expression)&&expression.trim().startsWith("${")){
                                Object str = variables.get(expression.substring(expression.lastIndexOf("{") + 1, expression.lastIndexOf("}")));
                                vo.setAssignee(JoeDevUtils.obj2Str(str));
                                vo.setAssigneeName(flowUserService.queryNameByUserIds(vo.getAssignee()));
                            }
                            list.add(vo);
                        }
                    }
                }
                Collections.sort(list, Comparator.comparing(FlowElementVo::getTaskKey));
            }
            return ResponseUtil.success(PageIntVo.create(list.size(),list));
        }catch (Exception e){
            log.error("获取流程的全部节点出错，流程processInstanceId="+processInstanceId,e);
            return ResponseUtil.error();
        }
    }

    @ApiOperation(value = "获取任务代办列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name="userId",value="用户id",paramType="query"),
            @ApiImplicitParam(name="pageNo",value="第几页，从1开始",required=true,paramType="query",dataType = "int",defaultValue = "1"),
            @ApiImplicitParam(name="pageSize",value="每页显示数",required=true,paramType="query",dataType = "int",defaultValue = "20")
    })
    @GetMapping("taskList")
    @ResponseBody
    public ResponseUtil<PageLongVo<TaskVo>> taskList(Integer pageNo,Integer pageSize,String userId) {
        try {
            List<TaskVo> taskVolist = new ArrayList<>();
            TaskQuery taskQuery = taskService.createTaskQuery();
            if(StrUtil.isNotEmpty(userId)){
                taskQuery.taskAssignee(userId);
            }
            //排序
            taskQuery.orderByTaskCreateTime().desc();
            //分页
            List<Task> taskList = taskQuery.listPage((pageNo - 1) * pageSize, pageSize);
            //构造数据
            for(Task item :taskList){
                TaskVo vo = new TaskVo(item);
                vo.setAssigneeName(flowUserService.queryNameByUserIds(vo.getAssignee()));
                ProcessInstance process = flowProcessService.getProcessInstanceById(item.getProcessInstanceId());
                ProcessDefinition definition = flowProcessService.getProcessDefinitionById(item.getProcessDefinitionId());
                vo.setProcessInstanceName(definition.getName());
                vo.setProcessInstanceDesc(definition.getDescription());
                vo.setProcessInstanceKey(definition.getKey());
                vo.setBusinessKey(process.getBusinessKey());
                vo.setDeploymentId(process.getDeploymentId());
                vo.setProcessStartTime(process.getStartTime());
                vo.setProcessStartUserId(process.getStartUserId());
                vo.setProcessStartUserName(flowUserService.queryNameByUserIds(vo.getProcessStartUserId()));
                taskVolist.add(vo);
            }
            return ResponseUtil.success(PageLongVo.create(taskQuery.count(),taskVolist));
        }catch (Exception e){
            log.error("获取审批的流程列表出错",e);
            return ResponseUtil.error();
        }
    }

    @ApiOperation(value = "获取审批历史列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name="processInstanceId",value="流程实例id",required=true,paramType="query")
    })
    @GetMapping("queryTaskCommentList")
    @ResponseBody
    public ResponseUtil<PageIntVo<TaskCommentVo>> queryTaskCommentList(String processInstanceId){
        try {
            List<TaskCommentVo> commentList = new ArrayList<>();
            QueryWrapper qw = new QueryWrapper();
            qw.eq("PROC_INST_ID_",processInstanceId);
            List<ActHiComment> list = actHiCommentMapper.selectList(qw);
            if(list!=null&&list.size()>0){
                Map<String, List<ActHiComment>> collect = list.stream().collect(Collectors.groupingBy(ActHiComment::getTaskId));
                for (String taskId : collect.keySet()) {
                    List<ActHiComment> subList = collect.get(taskId);
                    TaskCommentVo vo = getTaskCommentVo(taskId, subList);
                    commentList.add(vo);
                }
                Collections.sort(commentList, Comparator.comparing(TaskCommentVo::getCreateTime));
                Collections.reverse(commentList);
            }
            return ResponseUtil.success(PageIntVo.create(commentList.size(),commentList));
        }catch (Exception e){
            log.error("获取任务审批列表出错",e);
            return ResponseUtil.error();
        }
    }

    /**
     * 构造任务审批信息
     * @param taskId
     * @param subList
     * @return
     */
    private TaskCommentVo getTaskCommentVo(String taskId, List<ActHiComment> subList) {
        TaskCommentVo vo = new TaskCommentVo();
        HistoricTaskInstance task = historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult();
        if(task!=null){
            vo.setTaskKey(task.getTaskDefinitionKey());
            vo.setTaskName(task.getName());
            vo.setTaskTime(task.getCreateTime());
            vo.setAssignee(task.getAssignee());
            vo.setAssigneeName(flowUserService.queryNameByUserIds(vo.getAssignee()));
        }
        vo.setTaskId(taskId);
        for(ActHiComment item : subList){
            if("taskMessage".equals(item.getType())){
                vo.setTaskMessage(item.getMessage());
            }else if("taskStatus".equals(item.getType())){
                vo.setTaskStatus(item.getMessage());
            }else if("taskComment".equals(item.getType())){
                vo.setTaskComment(item.getMessage());
                vo.setCreateTime(item.getTime());
                vo.setUserId(item.getUserId());
                vo.setUserName(flowUserService.queryNameByUserIds(vo.getUserId()));
            }
        }
        return vo;
    }

}
